[libcxx] Fix SFINAE in <cmath>. Patch from K-Ballo. Delay instantiation of `__numeric_type` within <cmath>, don't instantiate it when the `is_arithmetic` conditions do not hold as it causes errors with user-defined types with ambiguous conversions. Fixes PR21083. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@219998 91177308-0d34-0410-b5e6-96231b3b80d8 
diff --git a/include/cmath b/include/cmath index 4719aba..d3aa4be 100644 --- a/include/cmath +++ b/include/cmath 
@@ -727,11 +727,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  atan2(_A1 __lcpp_y, _A2 __lcpp_x) _NOEXCEPT  { @@ -849,11 +849,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  fmod(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -952,11 +952,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  pow(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1114,11 +1114,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  copysign(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1192,11 +1192,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  fdim(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1216,12 +1216,12 @@    template <class _A1, class _A2, class _A3>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value &&  is_arithmetic<_A3>::value, - typename __promote<_A1, _A2, _A3>::type + __promote<_A1, _A2, _A3>  >::type  fma(_A1 __lcpp_x, _A2 __lcpp_y, _A3 __lcpp_z) _NOEXCEPT  { @@ -1242,11 +1242,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  fmax(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1266,11 +1266,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  fmin(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1290,11 +1290,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  hypot(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1459,11 +1459,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  nextafter(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1496,11 +1496,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  remainder(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT  { @@ -1520,11 +1520,11 @@    template <class _A1, class _A2>  inline _LIBCPP_INLINE_VISIBILITY -typename enable_if +typename __lazy_enable_if  <  is_arithmetic<_A1>::value &&  is_arithmetic<_A2>::value, - typename __promote<_A1, _A2>::type + __promote<_A1, _A2>  >::type  remquo(_A1 __lcpp_x, _A2 __lcpp_y, int* __lcpp_z) _NOEXCEPT  { 
diff --git a/include/type_traits b/include/type_traits index 5d21728..99cc7e1 100644 --- a/include/type_traits +++ b/include/type_traits 
@@ -218,6 +218,9 @@  template <bool _Bp, class _If, class _Then> using conditional_t = typename conditional<_Bp, _If, _Then>::type;  #endif   +template <bool, class _Tp> struct _LIBCPP_TYPE_VIS_ONLY __lazy_enable_if {}; +template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY __lazy_enable_if<true, _Tp> {typedef typename _Tp::type type;}; +  template <bool, class _Tp = void> struct _LIBCPP_TYPE_VIS_ONLY enable_if {};  template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY enable_if<true, _Tp> {typedef _Tp type;};   @@ -1208,43 +1211,46 @@  bool = __numeric_type<_A1>::value &&  __numeric_type<_A2>::value &&  __numeric_type<_A3>::value> -class __promote +class __promote_imp  { +public:  static const bool value = false;  };    template <class _A1, class _A2, class _A3> -class __promote<_A1, _A2, _A3, true> +class __promote_imp<_A1, _A2, _A3, true>  {  private: - typedef typename __promote<_A1>::type __type1; - typedef typename __promote<_A2>::type __type2; - typedef typename __promote<_A3>::type __type3; + typedef typename __promote_imp<_A1>::type __type1; + typedef typename __promote_imp<_A2>::type __type2; + typedef typename __promote_imp<_A3>::type __type3;  public:  typedef decltype(__type1() + __type2() + __type3()) type;  static const bool value = true;  };    template <class _A1, class _A2> -class __promote<_A1, _A2, void, true> +class __promote_imp<_A1, _A2, void, true>  {  private: - typedef typename __promote<_A1>::type __type1; - typedef typename __promote<_A2>::type __type2; + typedef typename __promote_imp<_A1>::type __type1; + typedef typename __promote_imp<_A2>::type __type2;  public:  typedef decltype(__type1() + __type2()) type;  static const bool value = true;  };    template <class _A1> -class __promote<_A1, void, void, true> +class __promote_imp<_A1, void, void, true>  {  public:  typedef typename __numeric_type<_A1>::type type;  static const bool value = true; - static const bool __does_not_throw = _NOEXCEPT_OR_FALSE(static_cast<type>(declval<_A1>()));  };   +template <class _A1, class _A2 = void, class _A3 = void> +class __promote : public __promote_imp<_A1, _A2, _A3> {}; +  #ifdef _LIBCPP_STORE_AS_OPTIMIZATION    // __transform